]>
Commit | Line | Data |
---|---|---|
c9b9ae52 A |
1 | /* |
2 | * Copyright (c) 2002-2003 Apple Computer, Inc. All rights reserved. | |
3 | * | |
4 | * @APPLE_LICENSE_HEADER_START@ | |
5 | * | |
6 | * This file contains Original Code and/or Modifications of Original Code | |
7 | * as defined in and that are subject to the Apple Public Source License | |
8 | * Version 2.0 (the 'License'). You may not use this file except in | |
9 | * compliance with the License. Please obtain a copy of the License at | |
10 | * http://www.opensource.apple.com/apsl/ and read it before using this | |
11 | * file. | |
12 | * | |
13 | * The Original Code and all software distributed under the License are | |
14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER | |
15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, | |
16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, | |
17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. | |
18 | * Please see the License for the specific language governing rights and | |
19 | * limitations under the License. | |
20 | * | |
21 | * @APPLE_LICENSE_HEADER_END@ | |
22 | ||
23 | Change History (most recent first): | |
24 | ||
25 | $Log: Mac\040OS\040Test\040Searcher.c,v $ | |
26 | Revision 1.13 2003/08/14 02:19:54 cheshire | |
27 | <rdar://problem/3375491> Split generic ResourceRecord type into two separate types: AuthRecord and CacheRecord | |
28 | ||
29 | Revision 1.12 2003/08/12 19:56:24 cheshire | |
30 | Update to APSL 2.0 | |
31 | ||
32 | */ | |
33 | ||
34 | #include <stdio.h> // For printf() | |
35 | #include <Events.h> // For WaitNextEvent() | |
36 | #include <SIOUX.h> // For SIOUXHandleOneEvent() | |
37 | ||
38 | #include "mDNSClientAPI.h" // Defines the interface to the client layer above | |
39 | #include "mDNSMacOS9.h" // Defines the specific types needed to run mDNS on this platform | |
40 | ||
41 | typedef struct | |
42 | { | |
43 | OTLIFO serviceinfolist; | |
44 | Boolean headerPrinted; | |
45 | Boolean lostRecords; | |
46 | } SearcherServices; | |
47 | ||
48 | typedef struct { ServiceInfo i; mDNSBool add; mDNSBool dom; OTLink link; } linkedServiceInfo; | |
49 | ||
50 | // These don't have to be globals, but their memory does need to remain valid for as | |
51 | // long as the search is going on. They are declared as globals here for simplicity. | |
52 | #define RR_CACHE_SIZE 1000 | |
53 | static CacheRecord rrcachestorage[RR_CACHE_SIZE]; | |
54 | static mDNS mDNSStorage; | |
55 | static mDNS_PlatformSupport PlatformSupportStorage; | |
56 | static SearcherServices services; | |
57 | static DNSQuestion browsequestion, domainquestion; | |
58 | ||
59 | // PrintServiceInfo prints the service information to standard out | |
60 | // A real application might want to do something else with the information | |
61 | static void PrintServiceInfo(SearcherServices *services) | |
62 | { | |
63 | OTLink *link = OTReverseList(OTLIFOStealList(&services->serviceinfolist)); | |
64 | ||
65 | while (link) | |
66 | { | |
67 | linkedServiceInfo *ls = OTGetLinkObject(link, linkedServiceInfo, link); | |
68 | ServiceInfo *s = &ls->i; | |
69 | ||
70 | if (!services->headerPrinted) | |
71 | { | |
72 | printf("%-55s Type Domain IP Address Port Info\n", "Name"); | |
73 | services->headerPrinted = true; | |
74 | } | |
75 | ||
76 | if (ls->dom) | |
77 | { | |
78 | char c_dom[256]; | |
79 | ConvertDomainNameToCString(&s->name, c_dom); | |
80 | if (ls->add) printf("%-55s available for browsing\n", c_dom); | |
81 | else printf("%-55s no longer available for browsing\n", c_dom); | |
82 | } | |
83 | else | |
84 | { | |
85 | domainlabel name; | |
86 | domainname type, domain; | |
87 | UInt16 port = (UInt16)((UInt16)s->port.b[0] << 8 | s->port.b[1]); | |
88 | char c_name[64], c_type[256], c_dom[256], c_ip[20]; | |
89 | ||
90 | DeconstructServiceName(&s->name, &name, &type, &domain); | |
91 | ConvertDomainLabelToCString_unescaped(&name, c_name); | |
92 | ConvertDomainNameToCString(&type, c_type); | |
93 | ConvertDomainNameToCString(&domain, c_dom); | |
94 | sprintf(c_ip, "%d.%d.%d.%d", s->ip.ip.v4.b[0], s->ip.ip.v4.b[1], s->ip.ip.v4.b[2], s->ip.ip.v4.b[3]); | |
95 | ||
96 | printf("%-55s %-16s %-14s ", c_name, c_type, c_dom); | |
97 | if (ls->add) printf("%-15s %5d %#s\n", c_ip, port, s->TXTinfo); | |
98 | else printf("Removed\n"); | |
99 | } | |
100 | ||
101 | link = link->fNext; | |
102 | OTFreeMem(ls); | |
103 | } | |
104 | } | |
105 | ||
106 | // When the name, address, port, and txtinfo for a service is found, FoundInstanceInfo() | |
107 | // enqueues a record for PrintServiceInfo() to print. | |
108 | // Note, a browsing application would *not* normally need to get all this information -- | |
109 | // all it needs is the name, to display to the user. | |
110 | // Finding out the address, port, and txtinfo should be deferred to the time that the user | |
111 | // actually needs to contact the service to use it. | |
112 | static void FoundInstanceInfo(mDNS *const m, ServiceInfoQuery *query) | |
113 | { | |
114 | SearcherServices *services = (SearcherServices *)query->ServiceInfoQueryContext; | |
115 | linkedServiceInfo *info = (linkedServiceInfo *)(query->info); | |
116 | if (query->info->ip.type == mDNSAddrType_IPv4) | |
117 | { | |
118 | mDNS_StopResolveService(m, query); // For this test code, one answer is sufficient | |
119 | OTLIFOEnqueue(&services->serviceinfolist, &info->link); | |
120 | OTFreeMem(query); | |
121 | } | |
122 | } | |
123 | ||
124 | // When a new named instance of a service is found, FoundInstance() is called. | |
125 | // In this sample code we turn around and immediately issue a query to resolve that service name to | |
126 | // find its address, port, and txtinfo, but a normal browing application would just display the name. | |
127 | static void FoundInstance(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) | |
128 | { | |
129 | #pragma unused (question) | |
130 | SearcherServices *services = (SearcherServices *)question->QuestionContext; | |
131 | linkedServiceInfo *info; | |
132 | ||
133 | debugf("FoundInstance %##s PTR %##s", answer->name.c, answer->rdata->u.name.c); | |
134 | ||
135 | if (answer->rrtype != kDNSType_PTR) return; | |
136 | if (!services) { debugf("FoundInstance: services is NULL"); return; } | |
137 | ||
138 | info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo)); | |
139 | if (!info) { services->lostRecords = true; return; } | |
140 | ||
141 | info->i.name = answer->rdata->u.name; | |
142 | info->i.InterfaceID = answer->InterfaceID; | |
143 | info->i.ip.type = mDNSAddrType_IPv4; | |
144 | info->i.ip.ip.v4 = zeroIPAddr; | |
145 | info->i.port = zeroIPPort; | |
146 | info->add = AddRecord; | |
147 | info->dom = mDNSfalse; | |
148 | ||
149 | if (!AddRecord) // If TTL == 0 we're deleting a service, | |
150 | OTLIFOEnqueue(&services->serviceinfolist, &info->link); | |
151 | else // else we're adding a new service | |
152 | { | |
153 | ServiceInfoQuery *q = (ServiceInfoQuery *)OTAllocMem(sizeof(ServiceInfoQuery)); | |
154 | if (!q) { OTFreeMem(info); services->lostRecords = true; return; } | |
155 | mDNS_StartResolveService(m, q, &info->i, FoundInstanceInfo, services); | |
156 | } | |
157 | } | |
158 | ||
159 | static void FoundDomain(mDNS *const m, DNSQuestion *question, const ResourceRecord *const answer, mDNSBool AddRecord) | |
160 | { | |
161 | #pragma unused (m) | |
162 | #pragma unused (question) | |
163 | SearcherServices *services = (SearcherServices *)question->QuestionContext; | |
164 | linkedServiceInfo *info; | |
165 | ||
166 | debugf("FoundDomain %##s PTR %##s", answer->name.c, answer->rdata->u.name.c); | |
167 | ||
168 | if (answer->rrtype != kDNSType_PTR) return; | |
169 | if (!services) { debugf("FoundDomain: services is NULL"); return; } | |
170 | ||
171 | info = (linkedServiceInfo *)OTAllocMem(sizeof(linkedServiceInfo)); | |
172 | if (!info) { services->lostRecords = true; return; } | |
173 | ||
174 | info->i.name = answer->rdata->u.name; | |
175 | info->i.InterfaceID = answer->InterfaceID; | |
176 | info->i.ip.type = mDNSAddrType_IPv4; | |
177 | info->i.ip.ip.v4 = zeroIPAddr; | |
178 | info->i.port = zeroIPPort; | |
179 | info->add = AddRecord; | |
180 | info->dom = mDNStrue; | |
181 | ||
182 | OTLIFOEnqueue(&services->serviceinfolist, &info->link); | |
183 | } | |
184 | ||
185 | // YieldSomeTime() just cooperatively yields some time to other processes running on classic Mac OS | |
186 | static Boolean YieldSomeTime(UInt32 milliseconds) | |
187 | { | |
188 | extern Boolean SIOUXQuitting; | |
189 | EventRecord e; | |
190 | WaitNextEvent(everyEvent, &e, milliseconds / 17, NULL); | |
191 | SIOUXHandleOneEvent(&e); | |
192 | return(SIOUXQuitting); | |
193 | } | |
194 | ||
195 | int main() | |
196 | { | |
197 | extern void mDNSPlatformIdle(mDNS *const m); // Only needed for debugging version | |
198 | mStatus err; | |
199 | Boolean DoneSetup = false; | |
200 | ||
201 | SIOUXSettings.asktosaveonclose = false; | |
202 | SIOUXSettings.userwindowtitle = "\pMulticast DNS Searcher"; | |
203 | SIOUXSettings.rows = 40; | |
204 | SIOUXSettings.columns = 132; | |
205 | ||
206 | printf("Prototype Multicast DNS Searcher\n\n"); | |
207 | printf("WARNING! This is experimental software.\n\n"); | |
208 | printf("Multicast DNS is currently an experimental protocol.\n\n"); | |
209 | printf("This software reports errors using MacsBug breaks,\n"); | |
210 | printf("so if you don't have MacsBug installed your Mac may crash.\n\n"); | |
211 | printf("******************************************************************************\n"); | |
212 | ||
213 | err = InitOpenTransport(); | |
214 | if (err) { debugf("InitOpenTransport failed %d", err); return(err); } | |
215 | ||
216 | err = mDNS_Init(&mDNSStorage, &PlatformSupportStorage, rrcachestorage, RR_CACHE_SIZE, | |
217 | mDNS_Init_DontAdvertiseLocalAddresses, mDNS_Init_NoInitCallback, mDNS_Init_NoInitCallbackContext); | |
218 | if (err) return(err); | |
219 | ||
220 | services.serviceinfolist.fHead = NULL; | |
221 | services.headerPrinted = false; | |
222 | services.lostRecords = false; | |
223 | ||
224 | while (!YieldSomeTime(35)) | |
225 | { | |
226 | // For debugging, use "#define __ONLYSYSTEMTASK__ 1" and call mDNSPlatformIdle() periodically. | |
227 | // For shipping code, don't define __ONLYSYSTEMTASK__, and you don't need to call mDNSPlatformIdle() | |
228 | mDNSPlatformIdle(&mDNSStorage); // Only needed for debugging version | |
229 | if (mDNSStorage.mDNSPlatformStatus == mStatus_NoError && !DoneSetup) | |
230 | { | |
231 | domainname srvtype, srvdom; | |
232 | DoneSetup = true; | |
233 | printf("\nSending mDNS service lookup queries and waiting for responses...\n\n"); | |
234 | MakeDomainNameFromDNSNameString(&srvtype, "_http._tcp."); | |
235 | MakeDomainNameFromDNSNameString(&srvdom, "local."); | |
236 | err = mDNS_StartBrowse(&mDNSStorage, &browsequestion, &srvtype, &srvdom, mDNSInterface_Any, FoundInstance, &services); | |
237 | if (err) break; | |
238 | err = mDNS_GetDomains(&mDNSStorage, &domainquestion, mDNS_DomainTypeBrowse, mDNSInterface_Any, FoundDomain, &services); | |
239 | if (err) break; | |
240 | } | |
241 | ||
242 | if (services.serviceinfolist.fHead) | |
243 | PrintServiceInfo(&services); | |
244 | ||
245 | if (services.lostRecords) | |
246 | { | |
247 | services.lostRecords = false; | |
248 | printf("**** Warning: Out of memory: Records have been missed.\n"); | |
249 | } | |
250 | } | |
251 | ||
252 | mDNS_StopBrowse(&mDNSStorage, &browsequestion); | |
253 | mDNS_Close(&mDNSStorage); | |
254 | return(0); | |
255 | } |